package com.heo.util;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.log4j.Logger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.heo.pojo.ControlInfoEntity;
import com.heo.pojo.StatusDictEntity;
import com.heo.pub.DictEnum;
import com.heo.pub.ServerConfig;
import com.heo.server.NettyServerSocketHandler;
import com.heo.task.CallBackTaskQueue;
import com.heo.task.thread.CallBackInfo;

import io.netty.channel.ChannelHandlerContext;

public class NettyChannelMapUtils {

	private static Logger logger = Logger.getLogger(NettyChannelMapUtils.class);
	private static Map<String, NettyServerSocketHandler> channelMaps = new ConcurrentHashMap<String, NettyServerSocketHandler>();
	// 目前有3种key
	// [DEVICE_CONTROL]appId+":"+imei号，这个key是用来保存设备的控制信息和状态。
	// [CALLBACK_INFO]appId+":"+imei号+":"+通道号，这个key是用来保存设备通道的回调信息
	// [LOCK_STATUS]appId+":"+imei号+":"+通道号，这个key是用来保存设备的锁状态（主要用来实现预约功能）
	private static final String DEVICE_CONTROL = "[DEVICE_CONTROL]";// 主要作用是防止保存的redis里的信息和其他的系统产生冲突
	private static final String CALLBACK_INFO = "[CALLBACK_INFO]";// 控制设备时，发过来的回调参数
	// 线程池
	public static ExecutorService sendTaskThreadPool = Executors.newFixedThreadPool(50);// 发送任务线程池

	public static synchronized void add(String appId, String deviceIMEI, int deviceChannelNum, short deviceType,
			NettyServerSocketHandler nettyServerSocketHandler) throws IOException {
		try {
			String deviceImei = DEVICE_CONTROL + appId + ":" + deviceIMEI;
			if (Utils.checkNull(deviceImei) && channelMaps.containsKey(deviceImei)) {
				NettyServerSocketHandler oNettyServerSocketHandler = get(appId, deviceIMEI);
				if (oNettyServerSocketHandler != null) {
					channelMaps.remove(deviceImei);
					oNettyServerSocketHandler.close();
				}
			}
			channelMaps.put(deviceImei, nettyServerSocketHandler);
			ControlInfoEntity controlInfo = new ControlInfoEntity();
			controlInfo.setControlUrl(ServerConfig.CONTROL_URL);
			controlInfo.setDeviceIMEI(deviceIMEI);
			controlInfo.setDeviceType(deviceType);
			controlInfo.setSocketChannelId(nettyServerSocketHandler.mCtx.channel().id().asShortText());

			for (int i = 0; i < deviceChannelNum; i++) {
				controlInfo.addChannelInfo(i, DictEnum.DeviceChannelStatusCode.FREE);
			}

			// 把设备的信息放到redis里
			String redisJson = JSON.toJSONString(controlInfo);
			RedisUtil.addValue(deviceImei, redisJson, ServerConfig.READ_IDLE_TIME);
			logger.debug("写入redis信息：" + redisJson);
		} catch (Exception e) {
			logger.error("NettyChannelMapUtils.add()出错，参数信息如下：");
			logger.error("channelMaps.size()=" + channelMaps.size());
			logger.error(e.getMessage(), e);
		}
	}

	public static synchronized Object getCallBackInfo(String appId, String deviceIMEI, int channelId) {
		// 从redis里获取回调参数
		Object callParaObj = RedisUtil
				.getValue(DictEnum.RedisKey.CALLBACK_INFO + appId + ":" + deviceIMEI + ":" + channelId);
		return callParaObj;
	}

	public static synchronized NettyServerSocketHandler get(String appId, String deviceIMEI) {
		String deviceImei = DEVICE_CONTROL + appId + ":" + deviceIMEI;
		if (deviceImei != null && !"".equals(deviceImei)) {
			return channelMaps.get(deviceImei);
		}
		return null;
	}

	public static synchronized void remove(String appId, String deviceIMEI) throws IOException {
		String deviceImei = DEVICE_CONTROL + appId + ":" + deviceIMEI;
		NettyServerSocketHandler nettyServerSocketHandler = get(appId, deviceIMEI);
		if (nettyServerSocketHandler != null) {
			channelMaps.remove(deviceImei);
			nettyServerSocketHandler.close();
			RedisUtil.remove(deviceImei);
			logger.info("netty remove imei = " + deviceImei);
		}
	}

	public static int getSocketSize() {
		return channelMaps.size();
	}

	/**
	 * 刷新设备在redis里的缓存时间
	 * 
	 * @param channelId
	 */
	public static void refreshDeviceControlInfoExpire(String appId, String deviceIMEI) {
		try {
			Object redisObj = RedisUtil.getValue(DEVICE_CONTROL + appId + ":" + deviceIMEI);
			if (redisObj == null) {
				remove(appId, deviceIMEI);
			} else {
				RedisUtil.expire(DEVICE_CONTROL + appId + ":" + deviceIMEI, ServerConfig.READ_IDLE_TIME);
				logger.info("NettyChannelMapUtils.refreshDeviceControlInfoExpire()时间 ：" + ServerConfig.READ_IDLE_TIME);
			}
		} catch (Exception e) {
			logger.error("NettyChannelMapUtils.refreshDeviceControlInfoExpire()出错，参数信息如下：");
			logger.error(e.getMessage(), e);
		}
	}

	public static ControlInfoEntity getDeviceControlInfoByIEMI(String appId, String deviceIMEI) {
		try {
			Object redisObj = RedisUtil.getValue(DEVICE_CONTROL + appId + ":" + deviceIMEI);
			if (redisObj == null) {
				return null;
			} else {
				return (ControlInfoEntity) JSON.parseObject(redisObj.toString(), ControlInfoEntity.class);
			}
		} catch (Exception e) {
			logger.error("SocketChannelMap.getDeviceByIEMI()出错，参数信息如下：");
			logger.error("socketMap.size()=" + channelMaps.size());
			logger.error(e.getMessage(), e);
			return null;
		}
	}

	/**
	 * 非原子操作，需要同步 刷新设备在redis里的状态
	 * 
	 * @param deviceIMEI
	 * @param channelId
	 * @param channelStatus
	 */
	public static synchronized void refreshDeviceStatus(String appId, String deviceIMEI, Integer deviceChannelId,
			byte channelStatus) {
		ControlInfoEntity controlInfo = getDeviceControlInfoByIEMI(appId, deviceIMEI);
		if (controlInfo == null) {
			// 不太可能出现这个情况。redis里取不到数据，应该是过期了。而过期的原因，一定是设备没有发消息上来。而没消息上来的话，链路会断开。
			// 链路一旦断开，链路里就没有这个设备的对象信息。因此也没办法创建新的控制信息对象了。
			logger.error("严重错误，redis里的设备控制信息丢失！");
			return;
		} else {
			controlInfo.setChannelStatus(deviceChannelId, channelStatus);
		}
		logger.info("刷新redis refreshDeviceStatus=" + JSON.toJSONString(controlInfo));
		// 把设备的信息放到redis里
		RedisUtil.addValue(DictEnum.RedisKey.DEVICE_CONTROL + appId + ":" + deviceIMEI, JSON.toJSONString(controlInfo),
				ServerConfig.READ_IDLE_TIME);
	}

	/**
	 * 非原子操作，需要同步 刷新设备在redis里的状态
	 * 
	 * @param deviceIMEI
	 * @param channelId
	 * @param channelStatus
	 */
	public static synchronized void refreshDeviceErrorStatus(String appId, String deviceIMEI, Integer deviceChannelId,
			byte channelStatus, String errorCode, String errorText) {
		ControlInfoEntity controlInfo = getDeviceControlInfoByIEMI(appId, deviceIMEI);
		if (controlInfo == null) {
			// 不太可能出现这个情况。redis里取不到数据，应该是过期了。而过期的原因，一定是设备没有发消息上来。而没消息上来的话，链路会断开。
			// 链路一旦断开，链路里就没有这个设备的对象信息。因此也没办法创建新的控制信息对象了。
			logger.error("严重错误，redis里的设备控制信息丢失！");
			return;
		} else {
			controlInfo.setChannelErrorStatus(deviceChannelId, channelStatus, errorCode, errorText);
		}
		logger.info("刷新redis refreshDeviceErrorStatus=" + JSON.toJSONString(controlInfo));
		// 把设备的信息放到redis里
		RedisUtil.addValue(DictEnum.RedisKey.DEVICE_CONTROL + appId + ":" + deviceIMEI, JSON.toJSONString(controlInfo),
				ServerConfig.READ_IDLE_TIME);
	}

	/**
	 * 设置callback参数，数据返回时，需要取出来回调
	 * 
	 * @param deviceIMEI
	 * @param deviceChannelId
	 * @param callbackPara
	 */
	public static void setCallBackPara(String appId, String deviceIMEI, Integer deviceChannelId, String callbackPara,
			long timeout) {
		RedisUtil.addValue(CALLBACK_INFO + appId + ":" + deviceIMEI + ":" + deviceChannelId, callbackPara, timeout);
	}

	/**
	 * 获得保存的callback参数
	 * 
	 * @param deviceIMEI
	 * @param deviceChannelId
	 * @return
	 */
	public static String getCallBackPara(String appId, String deviceIMEI, Integer deviceChannelId, short workStatus,
			String callBackType, int measure) {
		JSONObject json = new JSONObject();
		switch (callBackType) {
		case DictEnum.CallBackType.START_RESULT:
			json.put("callBackType", callBackType);
			json.put("deviceIMEI", deviceIMEI);
			json.put("deviceChannelIndex", deviceChannelId);
			json.put("resultCode", getStartResultCode(workStatus));
			json.put("resultMsg", getStartResultMsg(workStatus));
			json.put("measure", measure);
			Object obj1 = RedisUtil.getValue(CALLBACK_INFO + appId + ":" + deviceIMEI + ":" + deviceChannelId);
			if (obj1 != null) {
				json.put("callbackPara", obj1.toString());
			}
			return json.toString();

		case DictEnum.CallBackType.STATUS_REPORT:
			json.put("callBackType", callBackType);
			json.put("deviceIMEI", deviceIMEI);
			json.put("deviceChannelIndex", deviceChannelId);
			json.put("resultCode", getDeviceStatusResultCode(workStatus));
			json.put("resultMsg", getDeviceStatusResultMsg(workStatus));
			json.put("measure", measure);
			Object obj2 = RedisUtil.getValue(CALLBACK_INFO + appId + ":" + deviceIMEI + ":" + deviceChannelId);
			if (obj2 != null) {
				json.put("callbackPara", obj2.toString());
			}
			return json.toString();

		default:
			return null;
		}
	}

	public static String getCallBackPara(String appId, String deviceIMEI, Integer deviceChannelId, short workStatus,
			String callBackType) {
		JSONObject json = new JSONObject();
		switch (callBackType) {
		case DictEnum.CallBackType.START_RESULT:
			json.put("callBackType", callBackType);
			json.put("deviceIMEI", deviceIMEI);
			json.put("deviceChannelIndex", deviceChannelId);
			json.put("resultCode", getStartResultCode(workStatus));
			json.put("resultMsg", getStartResultMsg(workStatus));
			Object obj1 = RedisUtil.getValue(CALLBACK_INFO + appId + ":" + deviceIMEI + ":" + deviceChannelId);
			if (obj1 != null) {
				json.put("callbackPara", obj1.toString());
			}
			return json.toString();

		case DictEnum.CallBackType.STATUS_REPORT:
			json.put("callBackType", callBackType);
			json.put("deviceIMEI", deviceIMEI);
			json.put("deviceChannelIndex", deviceChannelId);
			json.put("resultCode", getDeviceStatusResultCode(workStatus));
			json.put("resultMsg", getDeviceStatusResultMsg(workStatus));
			Object obj2 = RedisUtil.getValue(CALLBACK_INFO + appId + ":" + deviceIMEI + ":" + deviceChannelId);
			if (obj2 != null) {
				json.put("callbackPara", obj2.toString());
			}
			return json.toString();

		default:
			return null;
		}
	}

	/**
	 * 获得保存的callback参数
	 * 
	 * @param deviceIMEI
	 * @param deviceChannelId
	 * @return
	 */
	public static String getCallBackPara(String appId, String deviceIMEI, Integer deviceChannelId, String resultCode,
			String resultMsg, String callBackType) {
		JSONObject json = new JSONObject();
		json.put("callBackType", callBackType);
		json.put("deviceIMEI", deviceIMEI);
		json.put("deviceChannelIndex", deviceChannelId);
		json.put("resultCode", resultCode);
		json.put("resultMsg", resultMsg);
		Object obj2 = RedisUtil.getValue(CALLBACK_INFO + appId + ":" + deviceIMEI + ":" + deviceChannelId);
		if (obj2 != null) {
			json.put("callbackPara", obj2.toString());
		}
		return json.toString();

	}

	/**
	 * 发送回调消息给服务器
	 * 
	 * @param appId
	 * @param deviceIMEI
	 * @param deviceChannelId
	 * @param callBackType
	 * @param cmd
	 * @param sendUrl
	 * @param statusDictMap
	 *            错误状态集合
	 */
	public static void errorCallBackSendStatus(String appId, String deviceIMEI, String callBackType, String errorCode,
			String sendUrl, Map<String, StatusDictEntity> statusDictMap) throws IOException {
		String deviceImei = DEVICE_CONTROL + appId + ":" + deviceIMEI;
		Object redisObj = RedisUtil.getValue(deviceImei);
		ControlInfoEntity controlInfoEntity = (ControlInfoEntity) JSON.parseObject(redisObj.toString(),
				ControlInfoEntity.class);
		int size = controlInfoEntity.getChannelInfoMap().size();
		if ("00000000".equals(errorCode)) {
			for (int i = 0; i < size; i++) {
				if (DictEnum.DeviceChannelStatusCode.DEVICE_CHANNEL_ERROR == controlInfoEntity.getChannelStatus(i)) {
					controlInfoEntity.setChannelStatus(i, DictEnum.DeviceChannelStatusCode.FREE);
				}
			}
			String redisJson = JSON.toJSONString(controlInfoEntity);
			RedisUtil.addValue(deviceImei, redisJson, ServerConfig.READ_IDLE_TIME);
			logger.debug("写入redis信息：" + redisJson);
		} else {
			StatusDictEntity statusDictEntity = statusDictMap.get(errorCode);
			if (statusDictEntity != null) {
				for (int i = 0; i < size; i++) {
					if (DictEnum.DeviceChannelStatusCode.DEVICE_CHANNEL_ERROR != controlInfoEntity
							.getChannelStatus(i)) {
						controlInfoEntity.setChannelStatus(i, DictEnum.DeviceChannelStatusCode.DEVICE_CHANNEL_ERROR);
						String sendMessage = getCallBackPara(appId, deviceIMEI, i, statusDictEntity.getMsgCode(),
								statusDictEntity.getMsgText(), callBackType);
						CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
						CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
					}
				}
				String redisJson = JSON.toJSONString(controlInfoEntity);
				RedisUtil.addValue(deviceImei, redisJson, ServerConfig.READ_IDLE_TIME);
			}
		}
	}
	
	/**
	 * 刷新设备的信号强度信息
	 * 
	 * @param channelId
	 */
	public static synchronized void updateDeviceSignal(String appId, String deviceIMEI, int signal,
			ChannelHandlerContext ctx) {
		try {
			ControlInfoEntity controlInfo = getDeviceControlInfoByIEMI(appId, deviceIMEI);
			if (controlInfo == null) {
				// 不太可能出现这个情况。redis里取不到数据，应该是过期了。而过期的原因，一定是设备没有发消息上来。而没消息上来的话，链路会断开。
				// 链路一旦断开，链路里就没有这个设备的对象信息。因此也没办法创建新的控制信息对象了。
				logger.error("严重错误，redis里的设备控制信息丢失！");
				if (ctx != null) {
					ctx.close();
				}
				return;
			} else {
				controlInfo.setSignal(signal);
			}
			// 把设备的信息放到redis里
			RedisUtil.addValue(DictEnum.RedisKey.DEVICE_CONTROL + appId + ":" + deviceIMEI,
					JSON.toJSONString(controlInfo), ServerConfig.READ_IDLE_TIME);
			logger.info("NettyChannelMapUtils.refreshDeviceControlInfoExpire()时间 ：" + ServerConfig.READ_IDLE_TIME);
		} catch (Exception e) {
			logger.error("NettyChannelMapUtils.refreshDeviceControlInfoExpire()出错，参数信息如下：");
			logger.error("channelMaps.size()=" + channelMaps.size());
			logger.error(e.getMessage(), e);
		}
	}
	
	/**
	 * 发送回调消息给服务器
	 * 
	 * @param appId
	 * @param deviceIMEI
	 * @param deviceChannelId
	 * @param callBackType
	 * @param cmd
	 * @param sendUrl
	 * @param statusDictMap
	 *            错误状态集合
	 */
	public static void callBackSendStatus(String appId, String deviceIMEI, Integer deviceChannelId, String callBackType,
			String cmd, String sendUrl, Map<String, StatusDictEntity> statusDictMap, ChannelHandlerContext ctx) {
		if("00".equals(cmd) || "03".equals(cmd)) {
			cmd = "01";
		}else if("01".equals(cmd) || "02".equals(cmd)) {
			cmd = "00";
		}
		
		// 这属于投币状态，不更新redis
		if (DictEnum.DeviceStatusCode.STARTING.equals(cmd)) {
			String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId, DictEnum.StartResultCode.SUCCESS,
					callBackType);
			CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
			CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
		} else {
			ControlInfoEntity controlInfoEntity = getDeviceControlInfoByIEMI(appId, deviceIMEI);
			if (controlInfoEntity != null) {
				short status = controlInfoEntity.getChannelStatus(deviceChannelId);
				logger.info("通道=" + deviceChannelId + ", 状态=" + status);
				// 工作中
				if (DictEnum.DeviceStatusCode.WORKING.equals(cmd)) {
					// 如果redis里面是空闲中，要改变状态并且回调
					if (DictEnum.DeviceChannelStatusCode.FREE == status) {
						String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
								DictEnum.DeviceChannelStatusCode.START_SUCCESS, callBackType);
						CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
						CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
						refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
								DictEnum.DeviceChannelStatusCode.WORKING, ctx);
						removeOrder(appId, deviceIMEI, deviceChannelId);
					} else if (DictEnum.DeviceChannelStatusCode.DEVICE_ERROR == status) {
						String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
								DictEnum.DeviceChannelStatusCode.WORKING, callBackType);
						CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
						CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
						refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
								DictEnum.DeviceChannelStatusCode.WORKING, ctx);
						removeOrder(appId, deviceIMEI, deviceChannelId);
					} else {
						NettyChannelMapUtils.refreshDeviceControlInfoExpire(appId, deviceIMEI);// 设备有消息上来，在redis里做延期
					}
				} else if (DictEnum.DeviceStatusCode.FREE.equals(cmd)) {
					// 如果redis里面是空闲工作中，要改变状态并且回调
					if (DictEnum.DeviceChannelStatusCode.WORKING == status
							|| DictEnum.DeviceChannelStatusCode.DEVICE_ERROR == status) {
						String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
								DictEnum.DeviceChannelStatusCode.WORK_DONE, callBackType);
						CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
						CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
						refreshDeviceStatus(appId, deviceIMEI, deviceChannelId, DictEnum.DeviceChannelStatusCode.FREE,
								ctx);
					} else {
						NettyChannelMapUtils.refreshDeviceControlInfoExpire(appId, deviceIMEI);// 设备有消息上来，在redis里做延期
					}
				} else {
					StatusDictEntity statusDictEntity = statusDictMap.get(cmd);
					if (statusDictEntity != null) {
						if (DictEnum.DeviceChannelStatusCode.FREE == status) {
							String sendMessageWork = getCallBackPara(appId, deviceIMEI, deviceChannelId,
									DictEnum.DeviceChannelStatusCode.START_SUCCESS, callBackType);
							CallBackInfo callBackInfoWork = new CallBackInfo(sendMessageWork, sendUrl);
							CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfoWork);

							String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
									statusDictEntity.getMsgCode(), statusDictEntity.getMsgText(), callBackType);
							CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
							callBackInfo.setSleepTime(3000);
							CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
						} else {
							removeOrder(appId, deviceIMEI, deviceChannelId);
							String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
									statusDictEntity.getMsgCode(), statusDictEntity.getMsgText(), callBackType);
							CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
							CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
						}
						refreshDeviceErrorStatus(appId, deviceIMEI, deviceChannelId,
								DictEnum.DeviceChannelStatusCode.DEVICE_ERROR, statusDictEntity.getMsgCode(),
								statusDictEntity.getMsgText());
					} else {
						NettyChannelMapUtils.refreshDeviceControlInfoExpire(appId, deviceIMEI);// 设备有消息上来，在redis里做延期
					}
				}
			}
		}
	}

//	public static void callBackSendStatus(String appId, String deviceIMEI, Integer deviceChannelId, String callBackType,
//			Integer cmd, String sendUrl) {
//		String cmds = "";
//		if (cmd == 2 || cmd == 3) {
//			cmds = "01";
//		} else if (cmd == 1 || cmd == 4) {
//			cmds = "00";
//		}  
//		if (DictEnum.DeviceStatusCode.STARTING.equals(cmds)) {
//			String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId, DictEnum.StartResultCode.SUCCESS,
//					callBackType);
//			CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
//			CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
//		} else {
//			ControlInfoEntity controlInfoEntity = getDeviceControlInfoByIEMI(appId, deviceIMEI);
//			if (controlInfoEntity != null) {
//				short status = controlInfoEntity.getChannelStatus(deviceChannelId);
//				logger.info("通道=" + deviceChannelId + ", 状态=" + status);
//				// 工作中
//				if (DictEnum.DeviceStatusCode.WORKING.equals(cmds)) {
//					// 如果redis里面是空闲中，要改变状态并且回调
//					if (DictEnum.DeviceChannelStatusCode.FREE == status) {
//						String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
//								DictEnum.DeviceChannelStatusCode.START_SUCCESS, callBackType);
//						CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
//						CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
//
////						refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
////								DictEnum.DeviceChannelStatusCode.START_SUCCESS);
////
////						String sendMessageWork = getCallBackPara(appId, deviceIMEI, deviceChannelId,
////								DictEnum.DeviceChannelStatusCode.WORKING, callBackType);
////						CallBackInfo callBackInfoWork = new CallBackInfo(sendMessageWork, sendUrl);
////						callBackInfoWork.setSleepTime(3000);
////						CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfoWork);
//						refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
//								DictEnum.DeviceChannelStatusCode.WORKING);
//					} else if (DictEnum.DeviceChannelStatusCode.DEVICE_ERROR == status) {
//						String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
//								DictEnum.DeviceChannelStatusCode.WORKING, callBackType);
//						CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
//						CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
//						refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
//								DictEnum.DeviceChannelStatusCode.WORKING);
//					}
//				} else if (DictEnum.DeviceStatusCode.FREE.equals(cmds)) {
//					// 如果redis里面是空闲工作中，要改变状态并且回调
//					if (DictEnum.DeviceChannelStatusCode.WORKING == status
//							|| DictEnum.DeviceChannelStatusCode.DEVICE_ERROR == status) {
//						String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
//								DictEnum.DeviceChannelStatusCode.WORK_DONE, callBackType);
//						CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
//						CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
//
////						refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
////								DictEnum.DeviceChannelStatusCode.WORK_DONE);
////						String sendMessageFree = getCallBackPara(appId, deviceIMEI, deviceChannelId,
////								DictEnum.DeviceChannelStatusCode.FREE, callBackType);
////						CallBackInfo callBackInfoFree = new CallBackInfo(sendMessageFree, sendUrl);
////						callBackInfoFree.setSleepTime(3000);
////						CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfoFree);
//						refreshDeviceStatus(appId, deviceIMEI, deviceChannelId, DictEnum.DeviceChannelStatusCode.FREE);
//					}
//				}
//			}
//		}
//	}

	/**
	 * 发送回调消息给服务器
	 * 
	 * @param appId
	 * @param deviceIMEI
	 * @param deviceChannelId
	 * @param callBackType
	 * @param cmd
	 * @param sendUrl
	 * @param statusDictMap
	 *            错误状态集合
	 */
	// public static void callBackSendStatus(String appId, String deviceIMEI,
	// Integer deviceChannelId, String callBackType,
	// String cmd, String sendUrl, Map<String, StatusDictEntity> statusDictMap) {
	// // 这属于投币状态，不更新redis
	// if (DictEnum.DeviceStatusCode.STARTING.equals(cmd)) {
	// String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
	// DictEnum.StartResultCode.SUCCESS,
	// callBackType);
	// CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
	// CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
	// } else {
	// ControlInfoEntity controlInfoEntity = getDeviceControlInfoByIEMI(appId,
	// deviceIMEI);
	// if (controlInfoEntity != null) {
	// short status = controlInfoEntity.getChannelStatus(deviceChannelId);
	// logger.info("通道=" + deviceChannelId + ", 状态=" + status);
	// // 工作中
	// if (DictEnum.DeviceStatusCode.WORKING.equals(cmd)) {
	// // 如果redis里面是空闲中，要改变状态并且回调
	// if (DictEnum.DeviceChannelStatusCode.FREE == status) {
	// String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.START_SUCCESS, callBackType);
	// CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
	// CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
	//
	// refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.START_SUCCESS);
	//
	// String sendMessageWork = getCallBackPara(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.WORKING, callBackType);
	// CallBackInfo callBackInfoWork = new CallBackInfo(sendMessageWork, sendUrl);
	// callBackInfoWork.setSleepTime(3000);
	// CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfoWork);
	// refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.WORKING);
	// } else if (DictEnum.DeviceChannelStatusCode.DEVICE_ERROR == status) {
	// String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.WORKING, callBackType);
	// CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
	// CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
	// refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.WORKING);
	// }
	// } else if (DictEnum.DeviceStatusCode.FREE.equals(cmd)) {
	// // 如果redis里面是空闲工作中，要改变状态并且回调
	// if (DictEnum.DeviceChannelStatusCode.WORKING == status
	// || DictEnum.DeviceChannelStatusCode.DEVICE_ERROR == status) {
	// String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.WORK_DONE, callBackType);
	// CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
	// CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
	//
	// refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.WORK_DONE);
	// String sendMessageFree = getCallBackPara(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.FREE, callBackType);
	// CallBackInfo callBackInfoFree = new CallBackInfo(sendMessageFree, sendUrl);
	// callBackInfoFree.setSleepTime(3000);
	// CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfoFree);
	// refreshDeviceStatus(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.FREE);
	// }
	// } else {
	// StatusDictEntity statusDictEntity = statusDictMap.get(cmd);
	// if (statusDictEntity != null) {
	// String sendMessage = getCallBackPara(appId, deviceIMEI, deviceChannelId,
	// statusDictEntity.getMsgCode(), statusDictEntity.getMsgText(), callBackType);
	// CallBackInfo callBackInfo = new CallBackInfo(sendMessage, sendUrl);
	// CallBackTaskQueue.getInstance().addCallBackMsg(callBackInfo);
	// refreshDeviceErrorStatus(appId, deviceIMEI, deviceChannelId,
	// DictEnum.DeviceChannelStatusCode.DEVICE_ERROR, statusDictEntity.getMsgCode(),
	// statusDictEntity.getMsgText());
	// }
	// }
	// }
	// }
	// }

	/**
	 * 非原子操作，需要同步 刷新设备在redis里的状态
	 * 
	 * @param deviceIMEI
	 * @param channelId
	 * @param channelStatus
	 */
	public static synchronized void refreshDeviceStatus(String appId, String deviceIMEI, Integer deviceChannelId,
			byte channelStatus, ChannelHandlerContext ctx) {
		ControlInfoEntity controlInfo = getDeviceControlInfoByIEMI(appId, deviceIMEI);
		if (controlInfo == null) {
			// 不太可能出现这个情况。redis里取不到数据，应该是过期了。而过期的原因，一定是设备没有发消息上来。而没消息上来的话，链路会断开。
			// 链路一旦断开，链路里就没有这个设备的对象信息。因此也没办法创建新的控制信息对象了。
			logger.error("严重错误，redis里的设备控制信息丢失！");
			if (ctx != null) {
				ctx.close();
			}
			return;
		} else {
			controlInfo.setChannelStatus(deviceChannelId, channelStatus);
		}
		logger.info("刷新redis refreshDeviceStatus=" + JSON.toJSONString(controlInfo));
		// 把设备的信息放到redis里
		RedisUtil.addValue(DictEnum.RedisKey.DEVICE_CONTROL + appId + ":" + deviceIMEI, JSON.toJSONString(controlInfo),
				ServerConfig.READ_IDLE_TIME);
	}
	
	private static String getStartResultCode(short workStatus) {
		switch (workStatus) {
		case DictEnum.StartResultCode.SUCCESS:
			return "SUCCESS";
		case DictEnum.StartResultCode.FAIL:
			return "FAIL";
		default:
			return "FAIL";
		}
	}

	private static String getStartResultMsg(short workStatus) {
		switch (workStatus) {
		case DictEnum.StartResultCode.SUCCESS:
			return DictEnum.StartResultMsg.SUCCESS;
		case DictEnum.StartResultCode.FAIL:
			return DictEnum.StartResultMsg.FAIL;
		default:
			return DictEnum.StartResultMsg.FAIL;
		}
	}

	private static String getDeviceStatusResultCode(short workStatus) {
		switch (workStatus) {
		case DictEnum.DeviceChannelStatusCode.DEVICE_CHANNEL_ERROR:
			return "DEVICE_CHANNEL_ERROR";
		case DictEnum.DeviceChannelStatusCode.DEVICE_ERROR:
			return "DEVICE_ERROR";
		case DictEnum.DeviceChannelStatusCode.FREE:
			return "FREE";
		case DictEnum.DeviceChannelStatusCode.START_SUCCESS:
			return "START_SUCCESS";
		case DictEnum.DeviceChannelStatusCode.WORK_DONE:
			return "WORK_DONE";
		case DictEnum.DeviceChannelStatusCode.WORKING:
			return "WORKING";
		default:
			return "UNKNOW_ERROR";
		}
	}

	private static String getDeviceStatusResultMsg(short workStatus) {
		switch (workStatus) {
		case DictEnum.DeviceChannelStatusCode.DEVICE_CHANNEL_ERROR:
			return DictEnum.DeviceChannelStatusMsg.DEVICE_CHANNEL_ERROR;
		case DictEnum.DeviceChannelStatusCode.DEVICE_ERROR:
			return DictEnum.DeviceChannelStatusMsg.DEVICE_ERROR;
		case DictEnum.DeviceChannelStatusCode.FREE:
			return DictEnum.DeviceChannelStatusMsg.FREE;
		case DictEnum.DeviceChannelStatusCode.START_SUCCESS:
			return DictEnum.DeviceChannelStatusMsg.START_SUCCESS;
		case DictEnum.DeviceChannelStatusCode.WORK_DONE:
			return DictEnum.DeviceChannelStatusMsg.WORK_DONE;
		case DictEnum.DeviceChannelStatusCode.WORKING:
			return DictEnum.DeviceChannelStatusMsg.WORKING;
		default:
			return DictEnum.DeviceChannelStatusMsg.UNKNOW_ERROR;
		}
	}
	
	private static void removeOrder(String appId, String deviceIMEI, Integer deviceChannelId) {
		Object obj1 = RedisUtil.getValue(CALLBACK_INFO + appId + ":" + deviceIMEI + ":" + deviceChannelId);
		if (obj1 != null) {
			JSONObject json = JSONObject.parseObject(obj1.toString());
			String orderId = json.getString("orderId");
			String meskey = DictEnum.RedisKey.ORDER + ":" + orderId;
			if (RedisUtil.getValue(meskey) != null) {
				RedisUtil.remove(meskey);
				meskey = meskey.replace(DictEnum.RedisKey.ORDER, DictEnum.RedisKey.ORDER_RESEND);
				RedisUtil.remove(meskey);
			}
		}
	}
}
